package center

import (
	"base"
	"center_server/chanrpc"
	"center_server/logic/center/api"
	"center_server/logic/center/handler"
	. "center_server/logic/internal"
	"encoding/json"
	"leaf/gate"
	"proto/base"
	"proto/server/center"
)

type centerSystem struct {
	agentId  base.AgentId
	servers  map[gate.Agent]proto_base.Server
	agents   map[base.AgentId]gate.Agent
	indexes  map[gate.Agent]base.AgentId
	handlers map[proto_base.Server]center_handler.Interface
}

var system = new(centerSystem)

func init() {
	system.servers = make(map[gate.Agent]proto_base.Server)
	system.agents = make(map[base.AgentId]gate.Agent)
	system.indexes = make(map[gate.Agent]base.AgentId)
	system.handlers = make(map[proto_base.Server]center_handler.Interface)
}

func init() {
	center_api.RegisterHandler = system.RegisterHandler
}

func init() {
	Skeleton.AfterInit(func() {
		Skeleton.RegisterChanRPC(chanrpc.NewAgent, system.newAgent)
		Skeleton.RegisterChanRPC(chanrpc.CloseAgent, system.closeAgent)
	})
}

func (*centerSystem) RegisterHandler(enum proto_base.Server, handler center_handler.Interface) {
	if _, exists := system.handlers[enum]; exists {
		base.Logger.Fatal("%s is exist", enum)
	}

	system.handlers[enum] = handler
}

func (*centerSystem) register(agent gate.Agent, server proto_base.Server, data []byte) {
	agentId := system.indexes[agent]
	handler, exists := system.handlers[server]
	if !exists {
		base.Logger.Error("undefined server handler: %s", server)
		return
	}

	result := handler.OnRegister(agentId, agent, data)
	if data, err := json.Marshal(result); err == nil {
		response := new(proto_server_center.OnRegister)
		response.AgentId = uint32(agentId)
		response.Data = data
		agent.WriteMsg(response)

		system.servers[agent] = server
	} else {
		base.Logger.Error("marshal error, %s", err)
	}
}

func (*centerSystem) newAgent(args []interface{}) {
	agent := args[0].(gate.Agent)
	base.Logger.Debug("new center agent, remote address: %s, local address: %s", agent.RemoteAddr(), agent.LocalAddr())

	agentId := system.getAgentId()
	system.agents[agentId] = agent
	system.indexes[agent] = agentId
}

func (*centerSystem) closeAgent(args []interface{}) {
	agent := args[0].(gate.Agent)
	base.Logger.Debug("close center agent, remote address: %s, local address: %s", agent.RemoteAddr(), agent.LocalAddr())

	agentId := system.indexes[agent]
	delete(system.agents, agentId)
	delete(system.indexes, agent)

	if t, exists := system.servers[agent]; exists {
		handler := system.handlers[t]
		handler.OnClose(agentId, agent)

		delete(system.servers, agent)
	}
}

func (*centerSystem) getAgentId() (result base.AgentId) {
	_, exists := system.agents[system.agentId]
	for exists {
		system.agentId++
		_, exists = system.agents[system.agentId]
	}

	result = system.agentId
	return
}
